﻿using AIVision.Model.MachineModels;
using AIVision.Model.EntityModels;
using AIVision.Model.UIModels;
using AIVision.PLC.LiWi;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AIVision.PLC.MachineModule
{
    public class TuLun
    {

        private IntPtr _handle;
        private PLCConfigDto plcConfig;
        private bool LoopReadFlag = false;
        private readonly TuLunStatusModel tuLunStatus;
        private readonly IEventAggregator eventAggregator;
        private readonly MachineStatusModel machineStatus;

        public bool TuLunGuanXH { 
            get {
                uint in5 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 5, ref in5);
                tuLunStatus.TuLunGuanXH = in5 == 1;
                return in5 == 1;
            }
        }
        public bool ShangLiaoXH
        {
            get
            {
                uint in6 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 6, ref in6);
                tuLunStatus.ShangLiaoXH = in6 == 1;
                return in6 == 1;
            }
        }

        public bool ServoRunXH
        {
            get
            {
                int runFlag = -1;
                Shell.PMC_GetIfIdle(_handle, 5, ref runFlag);
                tuLunStatus.ServoRunXH = runFlag == 0;
                return runFlag == 0;
            }
        }

        public Task RunTask { get; set; } = new Task(() => { });
        public TuLun(TuLunStatusModel tuLunStatus, IEventAggregator eventAggregator,MachineStatusModel machineStatus)
        {
            this.tuLunStatus = tuLunStatus;
            this.eventAggregator = eventAggregator;
            this.machineStatus = machineStatus;
        }
        public void Init(IntPtr _handle, PLCConfigDto plcConfig) 
        {
            this._handle = _handle;
            this.plcConfig = plcConfig;
        }

        public void ResetLocationAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(ResetLocation, CTS.Token);
                RunTask.Start();
            }
        }
        public void ResetLocation()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                int ret0 = Shell.PMC_SetAtype(_handle, 2, 1); // 设置轴 0 轴类型为 1 
                ret0 += Shell.PMC_SetInvertStep(_handle, 2, 1);
                ret0 += Shell.PMC_SetUnits(_handle, 2, 10); // 设置轴 0 脉冲当量为 100 
                ret0 += Shell.PMC_SetSpeed(_handle, 2, 360); // 设置轴 0 速度为 200units/s 
                Shell.PMC_SetAxisEnable(_handle, 2, 1);

                if (TuLunGuanXH)
                {
                    Shell.PMC_Single_Vmove(_handle, 2, 1);
                    timeout = 0;
                    while (TuLunGuanXH)
                        WaitTimeout(2000);
                    Shell.PMC_Single_Cancel(_handle, 2, 3);
                }
                if (!TuLunGuanXH)
                {
                    Shell.PMC_Single_Vmove(_handle, 2, 1);
                    timeout = 0;
                    while (!TuLunGuanXH)
                        WaitTimeout(2000);
                    Shell.PMC_Single_Cancel(_handle, 2, 3);
                }
                Shell.PMC_SetDpos(_handle, 2, 0); // 轴指令位置清 0 
                Shell.PMC_SetMpos(_handle, 2, 0); // 编码器反馈位置清 0 
                Shell.PMC_SetSpeed(_handle, 2, plcConfig.TuLunRunSpeed); // 设置轴 0 速度为 200units/s 
                Shell.PMC_SetAccel(_handle, 2, plcConfig.TuLunRunSpeed * 10); // 设置轴 0 加速度为 2000units/s/s 
                Shell.PMC_SetDecel(_handle, 2, plcConfig.TuLunRunSpeed * 10); // 设置轴 0 减速度为 2000units/s/s 
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 2, 3);
            }

        }
        public void RunOpenAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(RunOpen,CTS.Token);
                RunTask.Start();
            }
        }
        public void RunOpen()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                if (TuLunGuanXH)
                {
                    Shell.PMC_Single_MoveAbs(_handle, 2, 900);
                    timeout = 0;
                    while (ServoRunXH)
                        WaitTimeout(1000);
                }
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 2, 3);
            }
        }
        public void RunCloseAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(RunClose,CTS.Token);
                RunTask.Start();
            }
        }
        public void RunClose()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                if (!TuLunGuanXH)
                {
                    Shell.PMC_Single_MoveAbs(_handle, 2, 0);
                    timeout = 0;
                    while (ServoRunXH)
                        WaitTimeout(1000);
                }
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 2, 3);
            }
        }
        public void StepAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH && machineStatus.ResetLocationStatus)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(Step, CTS.Token);
                RunTask.Start();
            }
        }
        public void Step()
        {
            if (machineStatus.EmergencyStopXH && !machineStatus.ResetLocationStatus)
                return;
            if (TuLunGuanXH)
                RunOpen();
            else
            {
                RunClose();
            }
        }

        public void MonitorStatus()
        {
            float dpos = 0, mpos = 0, pfvalue = 0;
            Shell.PMC_GetDpos(_handle, 2, ref dpos);
            Shell.PMC_GetMpos(_handle, 2, ref mpos);
              Shell.PMC_GetMspeed(_handle, 2, ref pfvalue);
            tuLunStatus.DPos = dpos;
            tuLunStatus.MPos = mpos;
            tuLunStatus.Speed = pfvalue;

            var v = TuLunGuanXH;
            v = ShangLiaoXH;
            v = ServoRunXH;
        }

        #region WaitTimeout
        public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
        public delegate void TimeOutDelegate();
        private int timeout = 0;
        private void WaitTimeout(int waitTime, string msg = "", TimeOutDelegate timeOutDelegate = null)
        {
            // 检查是否请求取消
            CTS.Token.ThrowIfCancellationRequested();
            Task.Delay(1).Wait();
            timeout += 1;
            if (timeout > waitTime)
            {
                CTS.Cancel();
                if (timeOutDelegate != null)
                    timeOutDelegate();
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"等待超时:{msg}", "Red"));
            }
        } 
        #endregion
    }
}
